/*
 * Copyright 2008 Nathan C Jones
 * 
 * This file is part of Fivehundred.
 * 
 * Fivehundred is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * Fivehundred is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * Fivehundred. If not, see <http://www.gnu.org/licenses/>. 
 */

package com.googlecode.fivehundred.ui;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;

import javax.swing.JPanel;

/**
 * A swing component which contains a single composite graphical component.
 * 
 * @author Nathan C Jones
 */
public class GraphicsCanvas extends JPanel {

	/** Serial Version UID 2007-11-07 */
	private static final long serialVersionUID = 1852904436712495347L;

	/** The graphical composite rendered by this canvas. */
	private final GraphicalComponent component;

	/** The root composite of the canvas. */
	private CanvasRootComponent canvasRootComponent;

	/**
	 * Create a new graphics canvas for painting the given graphical composite.
	 * 
	 * @param component the graphical composite to be painted by the canvas.
	 */
	public GraphicsCanvas(GraphicalComponent component) {
		this.component = component;
		canvasRootComponent = new CanvasRootComponent();
		canvasRootComponent.add(component);
		addMouseListener(mouseListener);
		addMouseMotionListener(mouseListener);
	}

	/**
	 * Get the graphical composite painted by the canvas.
	 * 
	 * @return the canvas' graphical component.
	 */
	public GraphicalComponent getComponent() {
		return component;
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		component.paint((Graphics2D) g, 0, 0, 0);
	}

	/**
	 * The root component, added as the parent of the composite used to construct
	 * a canvas. Allows child components to trigger a repaint and find their
	 * absolute position.
	 */
	private class CanvasRootComponent extends CompositeGraphicalComponent {
		@Override
		void repaint() {
			GraphicsCanvas.this.repaint();
		}

		@Override
		public double getAbsoluteAngle() {
			return 0d;
		}

		@Override
		public Point getAbsolutePosition() {
			return new Point(0, 0);
		}
	}

	private final MouseAdapter mouseListener = new MouseAdapter() {
		private GraphicalComponent current = null;

		private GraphicalComponent entered = null;

		@Override
		public void mouseClicked(MouseEvent e) {
			current = getComponentAt(e.getPoint());
			processMouseEvent(e);
		}

		@Override
		public void mousePressed(MouseEvent e) {
			current = getComponentAt(e.getPoint());
			processMouseEvent(e);
		}

		@Override
		public void mouseReleased(MouseEvent e) {
			processMouseEvent(e);
		}

		@Override
		public void mouseDragged(MouseEvent e) {
			processMouseEvent(e);
		}

		@Override
		public void mouseMoved(MouseEvent e) {
			System.out.println("mouse moved");
			current = getComponentAt(e.getPoint());
			System.out.println(current);
			// simulate mouse enter / exit events
			if (current != entered) {
				if (entered != null) {
					entered.processMouseEvent(new MouseEvent(GraphicsCanvas.this, MouseEvent.MOUSE_EXITED, System.currentTimeMillis(), 0, e
							.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), 0, false, 0));
					// TODO remember the last position
				}
				if (current != null) {
					current.processMouseEvent(new MouseEvent(GraphicsCanvas.this, MouseEvent.MOUSE_ENTERED, System.currentTimeMillis(), 0, e
							.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), 0, false, 0));
				}
				entered = current;
			}
			processMouseEvent(e);
		}

		@Override
		public void mouseWheelMoved(MouseWheelEvent e) {
		}

		private void processMouseEvent(MouseEvent e) {
			if (current != null) {
				current.processMouseEvent(e);
			}
		}

		private GraphicalComponent getComponentAt(Point p) {
			return canvasRootComponent.getComponentAt(p, 0, 0, 0);
		}
	};

}
